Išnagrinėkite React `useActionState` kabliuką, skirtą supaprastintam būsenos valdymui, kurį sukelia asinchroniniai veiksmai. Pagerinkite savo programos efektyvumą ir vartotojo patirtį.
React useActionState įgyvendinimas: veiksmais pagrįstas būsenos valdymas
React useActionState kabliukas, pristatytas naujausiose versijose, siūlo patobulintą būdą valdyti būsenos atnaujinimus, atsirandančius dėl asinchroninių veiksmų. Šis galingas įrankis supaprastina mutacijų tvarkymo, vartotojo sąsajos (UI) atnaujinimo ir klaidų būsenų valdymo procesą, ypač dirbant su React Server Components (RSC) ir serverio veiksmais. Šiame vadove bus nagrinėjamos useActionState subtilybės, pateikiami praktiniai pavyzdžiai ir geriausios įgyvendinimo praktikos.
Veiksmais pagrįsto būsenos valdymo poreikio supratimas
Tradicinis React būsenos valdymas dažnai apima krovimo ir klaidų būsenų valdymą atskirai komponentuose. Kai veiksmas (pvz., formos pateikimas, duomenų gavimas) sukelia būsenos atnaujinimą, programuotojai paprastai valdo šias būsenas su keliais useState iškvietimais ir potencialiai sudėtinga sąlygine logika. useActionState siūlo švaresnį ir labiau integruotą sprendimą.
Apsvarstykime paprastą formos pateikimo scenarijų. Be useActionState, jūs tikriausiai turėtumėte:
- Būsenos kintamąjį formos duomenims.
- Būsenos kintamąjį, kuris seka, ar forma yra teikiama (krovimo būsena).
- Būsenos kintamąjį, kuriame saugomi klaidų pranešimai.
Šis požiūris gali lemti išpūstą kodą ir galimus neatitikimus. useActionState sujungia šiuos aspektus į vieną kabliuką, supaprastindamas logiką ir gerindamas kodo skaitomumą.
Pristatome useActionState
useActionState kabliukas priima du argumentus:
- Asinchroninę funkciją („veiksmą“), kuri atlieka būsenos atnaujinimą. Tai gali būti serverio veiksmas arba bet kokia asinchroninė funkcija.
- Pradinę būsenos reikšmę.
Jis grąžina masyvą, kuriame yra du elementai:
- Dabartinę būsenos reikšmę.
- Funkciją veiksmui išsiųsti. Ši funkcija automatiškai valdo su veiksmu susijusias krovimo ir klaidų būsenas.
Štai pagrindinis pavyzdys:
import { useActionState } from 'react';
async function updateServer(prevState, formData) {
// Simulate an asynchronous server update.
await new Promise(resolve => setTimeout(resolve, 1000));
const data = Object.fromEntries(formData);
if (data.name === "error") {
return 'Failed to update server.';
}
return `Updated name to: ${data.name}`;
}
function MyComponent() {
const [state, dispatch] = useActionState(updateServer, 'Initial State');
async function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
const result = await dispatch(formData);
console.log(result);
}
return (
);
}
Šiame pavyzdyje:
updateServeryra asinchroninis veiksmas, kuris imituoja serverio atnaujinimą. Jis gauna ankstesnę būseną ir formos duomenis.useActionStateinicializuoja būseną su 'Initial State' ir grąžina dabartinę būseną beidispatchfunkciją.handleSubmitfunkcija iškviečiadispatchsu formos duomenimis.useActionStateautomatiškai tvarko krovimo ir klaidų būsenas veiksmo vykdymo metu.
Krovimo ir klaidų būsenų tvarkymas
Vienas iš pagrindinių useActionState privalumų yra integruotas krovimo ir klaidų būsenų valdymas. dispatch funkcija grąžina pažadą (promise), kuris išsipildo su veiksmo rezultatu. Jei veiksmas išmeta klaidą, pažadas atmetamas su ta klaida. Galite tai naudoti atitinkamai atnaujindami vartotojo sąsają.
Pakeiskime ankstesnį pavyzdį, kad būtų rodomas krovimo pranešimas ir klaidos pranešimas:
import { useActionState } from 'react';
import { useState } from 'react';
async function updateServer(prevState, formData) {
// Simulate an asynchronous server update.
await new Promise(resolve => setTimeout(resolve, 1000));
const data = Object.fromEntries(formData);
if (data.name === "error") {
throw new Error('Failed to update server.');
}
return `Updated name to: ${data.name}`;
}
function MyComponent() {
const [state, dispatch] = useActionState(updateServer, 'Initial State');
const [isSubmitting, setIsSubmitting] = useState(false);
const [errorMessage, setErrorMessage] = useState(null);
async function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
setIsSubmitting(true);
setErrorMessage(null);
try {
const result = await dispatch(formData);
console.log(result);
} catch (error) {
console.error("Error during submission:", error);
setErrorMessage(error.message);
} finally {
setIsSubmitting(false);
}
}
return (
);
}
Pagrindiniai pakeitimai:
- Pridėjome
isSubmittingirerrorMessagebūsenos kintamuosius, kad sektume krovimo ir klaidų būsenas. handleSubmitfunkcijoje nustatomeisSubmittingįtrueprieš iškviečiantdispatchir gaudome bet kokias klaidas, kad atnaujintumeerrorMessage.- Išjungiame pateikimo mygtuką, kol vyksta pateikimas, ir sąlygiškai rodome krovimo bei klaidų pranešimus.
useActionState su serverio veiksmais React Server Components (RSC)
useActionState ypač naudingas, kai naudojamas su React Server Components (RSC) ir serverio veiksmais. Serverio veiksmai yra funkcijos, kurios veikia serveryje ir gali tiesiogiai keisti duomenų šaltinius. Jie leidžia atlikti serverio pusės operacijas nerašant API galinių punktų.
Pastaba: Šiam pavyzdžiui reikalinga React aplinka, sukonfigūruota Server Components ir Server Actions.
// app/actions.js (Server Action)
'use server';
import { cookies } from 'next/headers'; //Example, for Next.js
export async function updateName(prevState, formData) {
const name = formData.get('name');
if (!name) {
return 'Please enter a name.';
}
try {
// Simulate database update.
await new Promise(resolve => setTimeout(resolve, 1000));
cookies().set('userName', name);
return `Updated name to: ${name}`; //Success!
} catch (error) {
console.error("Database update failed:", error);
return 'Failed to update name.'; // Important: Return a message, not throw an Error
}
}
// app/page.jsx (React Server Component)
'use client';
import { useActionState } from 'react';
import { updateName } from './actions';
function MyComponent() {
const [state, dispatch] = useActionState(updateName, 'Initial State');
async function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
const result = await dispatch(formData);
console.log(result);
}
return (
);
}
export default MyComponent;
Šiame pavyzdyje:
updateNameyra serverio veiksmas, apibrėžtasapp/actions.js. Jis gauna ankstesnę būseną ir formos duomenis, atnaujina duomenų bazę (imituotai) ir grąžina sėkmės arba klaidos pranešimą. Svarbiausia, kad veiksmas grąžina pranešimą, o ne išmeta klaidą. Serverio veiksmai teikia pirmenybę informatyvių pranešimų grąžinimui.- Komponentas yra pažymėtas kaip kliento komponentas (
'use client'), kad būtų galima naudotiuseActionStatekabliuką. handleSubmitfunkcija iškviečiadispatchsu formos duomenimis.useActionStateautomatiškai valdo būsenos atnaujinimą, remdamasis serverio veiksmo rezultatu.
Svarbūs aspektai dirbant su serverio veiksmais
- Klaidų apdorojimas serverio veiksmuose: Užuot išmetę klaidas, grąžinkite prasmingą klaidos pranešimą iš savo serverio veiksmo.
useActionStatetraktuos šį pranešimą kaip naują būseną. Tai leidžia sklandžiai apdoroti klaidas kliento pusėje. - Optimistiniai atnaujinimai: Serverio veiksmai gali būti naudojami su optimistiniu atnaujinimu, siekiant pagerinti suvokiamą našumą. Galite nedelsiant atnaujinti UI ir atšaukti pakeitimus, jei veiksmas nepavyksta.
- Pakartotinis patvirtinimas (Revalidation): Po sėkmingos mutacijos apsvarstykite galimybę pakartotinai patvirtinti talpykloje esančius duomenis, kad užtikrintumėte, jog UI atspindi naujausią būseną.
Pažangios useActionState technikos
1. Reducer naudojimas sudėtingiems būsenos atnaujinimams
Sudėtingesnei būsenos logikai galite derinti useActionState su reducer funkcija. Tai leidžia valdyti būsenos atnaujinimus nuspėjamu ir palaikomu būdu.
import { useActionState } from 'react';
import { useReducer } from 'react';
const initialState = {
count: 0,
message: 'Initial State',
};
function reducer(state, action) {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
case 'DECREMENT':
return { ...state, count: state.count - 1 };
case 'SET_MESSAGE':
return { ...state, message: action.payload };
default:
return state;
}
}
async function updateState(state, action) {
// Simulate asynchronous operation.
await new Promise(resolve => setTimeout(resolve, 500));
switch (action.type) {
case 'INCREMENT':
return reducer(state, action);
case 'DECREMENT':
return reducer(state, action);
case 'SET_MESSAGE':
return reducer(state, action);
default:
return state;
}
}
function MyComponent() {
const [state, dispatch] = useActionState(updateState, initialState);
return (
Count: {state.count}
Message: {state.message}
);
}
2. Optimistiniai atnaujinimai su useActionState
Optimistiniai atnaujinimai pagerina vartotojo patirtį, nedelsiant atnaujinant UI, lyg veiksmas būtų pavykęs, ir atšaukiant atnaujinimą, jei veiksmas nepavyksta. Dėl to jūsų programa gali atrodyti jautresnė.
import { useActionState } from 'react';
import { useState } from 'react';
async function updateServer(prevState, formData) {
// Simulate an asynchronous server update.
await new Promise(resolve => setTimeout(resolve, 1000));
const data = Object.fromEntries(formData);
if (data.name === "error") {
throw new Error('Failed to update server.');
}
return `Updated name to: ${data.name}`;
}
function MyComponent() {
const [name, setName] = useState('Initial Name');
const [state, dispatch] = useActionState(async (prevName, newName) => {
try {
const result = await updateServer(prevName, {
name: newName,
});
return newName; // Update on success
} catch (error) {
// Revert on error
console.error("Update failed:", error);
setName(prevName);
return prevName;
}
}, name);
async function handleSubmit(event) {
event.preventDefault();
const formData = new FormData(event.target);
const newName = formData.get('name');
setName(newName); // Optimistically update UI
await dispatch(newName);
}
return (
);
}
3. Veiksmų delsos (Debouncing) taikymas
Kai kuriais atvejais galbūt norėsite taikyti veiksmų delsą (debounce), kad išvengtumėte per dažno jų išsiuntimo. Tai gali būti naudinga tokiuose scenarijuose kaip paieškos laukeliai, kur norite suaktyvinti veiksmą tik tada, kai vartotojas nustoja spausdinti tam tikrą laiką.
import { useActionState } from 'react';
import { useState, useEffect } from 'react';
async function searchItems(prevState, query) {
// Simulate asynchronous search.
await new Promise(resolve => setTimeout(resolve, 500));
return `Search results for: ${query}`;
}
function MyComponent() {
const [query, setQuery] = useState('');
const [state, dispatch] = useActionState(searchItems, 'Initial State');
useEffect(() => {
const timeoutId = setTimeout(() => {
if (query) {
dispatch(query);
}
}, 300); // Debounce for 300ms
return () => clearTimeout(timeoutId);
}, [query, dispatch]);
return (
setQuery(e.target.value)}
/>
State: {state}
);
}
Geriausios useActionState praktikos
- Išlaikykite veiksmų grynumą: Užtikrinkite, kad jūsų veiksmai būtų grynosios funkcijos (arba kuo artimesnės joms). Jos neturėtų turėti šalutinių poveikių, išskyrus būsenos atnaujinimą.
- Sklandžiai tvarkykite klaidas: Visada apdorokite klaidas savo veiksmuose ir pateikite vartotojui informatyvius klaidų pranešimus. Kaip minėta anksčiau apie serverio veiksmus, pirmenybę teikite klaidos pranešimo eilutės grąžinimui iš serverio veiksmo, o ne klaidos išmetimui.
- Optimizuokite našumą: Atsižvelkite į savo veiksmų našumo pasekmes, ypač dirbant su dideliais duomenų rinkiniais. Apsvarstykite galimybę naudoti memoizacijos technikas, kad išvengtumėte nereikalingų pervaizdavimų.
- Atsižvelkite į prieinamumą: Užtikrinkite, kad jūsų programa būtų prieinama visiems vartotojams, įskaitant turinčius negalią. Pateikite atitinkamus ARIA atributus ir klaviatūros navigaciją.
- Kruopštus testavimas: Rašykite vienetų testus (unit tests) ir integracijos testus, kad užtikrintumėte, jog jūsų veiksmai ir būsenos atnaujinimai veikia teisingai.
- Internacionalizacija (i18n): Globalioms programoms įdiekite i18n, kad palaikytumėte kelias kalbas ir kultūras.
- Lokalizacija (l10n): Pritaikykite savo programą konkrečioms vietovėms, pateikdami lokalizuotą turinį, datų formatus ir valiutų simbolius.
useActionState palyginimas su kitais būsenos valdymo sprendimais
Nors useActionState suteikia patogų būdą valdyti veiksmais pagrįstus būsenos atnaujinimus, jis nepakeičia visų būsenos valdymo sprendimų. Sudėtingoms programoms su globalia būsena, kurią reikia bendrinti tarp kelių komponentų, bibliotekos, tokios kaip Redux, Zustand ar Jotai, gali būti tinkamesnės.
Kada naudoti useActionState:
- Paprasto ar vidutinio sudėtingumo būsenos atnaujinimams.
- Būsenos atnaujinimams, glaudžiai susijusiems su asinchroniniais veiksmais.
- Integracijai su React Server Components ir Server Actions.
Kada apsvarstyti kitus sprendimus:
- Sudėtingam globalios būsenos valdymui.
- Būsenai, kurią reikia bendrinti tarp daugybės komponentų.
- Pažangioms funkcijoms, tokioms kaip laiko kelionių derinimas (time-travel debugging) ar tarpinė programinė įranga (middleware).
Išvada
React useActionState kabliukas siūlo galingą ir elegantišką būdą valdyti būsenos atnaujinimus, kuriuos sukelia asinchroniniai veiksmai. Sujungdamas krovimo ir klaidų būsenas, jis supaprastina kodą ir pagerina skaitomumą, ypač dirbant su React Server Components ir serverio veiksmais. Supratimas apie jo stipriąsias ir silpnąsias puses leidžia pasirinkti tinkamą būsenos valdymo metodą jūsų programai, o tai veda prie lengviau prižiūrimo ir efektyvesnio kodo.
Laikydamiesi šiame vadove aprašytų geriausių praktikų, galite efektyviai panaudoti useActionState, kad pagerintumėte savo programos vartotojo patirtį ir kūrimo eigą. Nepamirškite atsižvelgti į savo programos sudėtingumą ir pasirinkti būsenos valdymo sprendimą, kuris geriausiai atitinka jūsų poreikius. Nuo paprastų formų pateikimo iki sudėtingų duomenų mutacijų, useActionState gali būti vertingas įrankis jūsų React kūrimo arsenale.